import { Injectable } from '@nestjs/common';
import * as fs from 'fs';
import * as path from 'path';
import * as xlsx from 'xlsx-js-style';
import dayjs from 'dayjs';
import * as _ from 'lodash';
import {
  fileRename,
  getExtname,
  getFilePath,
  getFileType,
  getSize,
  saveLocalFile,
} from '~/utils/file.util';

@Injectable()
export class ExcelService {
  constructor() {}

  async downloadTemplate() {
    const url = process.env.APP_BASE_URL + '/template/表格模板.xlsx';
    return url;
  }

  // 定义默认样式
  private _defaultStyles = {
    titleStyle: {
      font: { bold: true, color: { rgb: '000000' }, size: 14 },
      alignment: { horizontal: 'center' },
      fill: { fgColor: { rgb: 'FFFF00' } },
    },
    bodyStyle: {
      font: { color: { rgb: '000000' }, size: 12 },
      alignment: { horizontal: 'left', vertical: 'middle' }, // 添加垂直居中对齐
    },
  };

  /**
   * 创建一个带有样式的 Excel 文件
   * @param {string[]} headers - 表头数组
   * @param {Object[]} data - 数据数组
   * @param {Object} styles - 样式定义对象
   * @param {string} outputFileName - 输出文件名
   * @param {string[]} sortArr - 排序数组
   * @param {string} fileType - 文件类型 （比如考勤 就是 attendance 为了区分文件夹）
   */
  async createStyledExcel(headers, data, outputFileName, sortArr?) {
    const styles = this._defaultStyles;

    // 定义格式
    const excelType = 'xlsx';

    // 创建一个新的工作簿
    const wb = xlsx.utils.book_new();

    // 数据处理排序
    if (sortArr) {
      data = this.sortAndFilterObjects(data, sortArr);
    }

    // 提取表头
    const dataHeaders = !_.isEmpty(data) ? Object.keys(data[0]) : [];
    // 转换数据
    const changData = data.map(item =>
      dataHeaders.map(header => {
        const value = item[header];
        if (value instanceof Date) {
          return dayjs(value).format('YYYY-MM-DD');
        }
        // 将所有值转换为字符串
        return value;
      }),
    );

    // 创建一个新的工作表，包含表头和数据
    const ws = xlsx.utils.aoa_to_sheet([headers, ...changData]);

    // 应用表头样式
    const headerRange = xlsx.utils.decode_range(ws['!ref']);
    for (let C = headerRange.s.c; C <= headerRange.e.c; ++C) {
      const cell_address = xlsx.utils.encode_cell({ r: 0, c: C });
      if (ws[cell_address]) {
        ws[cell_address].s = styles.titleStyle;
      }
    }

    // 应用正文样式（从第二行开始）
    for (let R = 1; R <= headerRange.e.r; ++R) {
      for (let C = headerRange.s.c; C <= headerRange.e.c; ++C) {
        const cell_address = xlsx.utils.encode_cell({ r: R, c: C });
        if (ws[cell_address]) {
          ws[cell_address].s = styles.bodyStyle;
          ws[cell_address].s.alignment = {
            ...styles.bodyStyle.alignment,
            wrapText: true,
          }; // 启用自动换行
          ws[cell_address].t = 's'; // 显式设置单元格类型为字符串
          ws[cell_address].z = '@'; // 强制单元格显示为文本
        }
      }
    }

    // 设置列宽自适应
    ws['!cols'] = dataHeaders.map(() => ({ width: 20 })); // 初始宽度设为20
    dataHeaders.forEach((header, index) => {
      let maxLength = 0;
      [headers[index], ...changData.map(row => row[index])].forEach(
        cellValue => {
          const columnLength = cellValue ? cellValue.toString().length : 10; // 默认最小宽度
          if (columnLength > maxLength) {
            maxLength = columnLength;
          }
        },
      );
      ws['!cols'][index] = { width: maxLength < 30 ? maxLength + 2 : 30 }; // 最大宽度限制
    });

    // 将工作表添加到工作簿
    xlsx.utils.book_append_sheet(wb, ws, 'Sheet1');

    const type = '表格';
    const currentDate = dayjs().format('YYYY-MM-DD');
    //重新修改文件名称
    const name = fileRename(outputFileName);
    const url = getFilePath(name, currentDate, type);

    // 使用 process.cwd() 确保路径从项目根目录开始
    const filePath = path.resolve(
      process.cwd(),
      'public/upload/',
      currentDate,
      type,
    );

    try {
      // 判断是否有该文件夹
      await fs.promises.stat(filePath);
    } catch (error) {
      // 没有该文件夹就创建
      await fs.promises.mkdir(filePath, { recursive: true });
    }

    // outputFileName 是文件名称
    try {
      // 写文件
      await xlsx.writeFile(wb, path.resolve(filePath, name), {
        bookType: excelType,
      });
    } catch (e) {
      console.log(e);
    }
    // console.log(`Excel 文件已成功保存到 ${process.env.APP_BASE_URL}${url}`);
    return url;
  }

  // 将数据转换为jsondata
  async handleExcelFile(file: Express.Multer.File) {
    // 创建一个二进制数组来存储文件数据
    const data = new Uint8Array(file.buffer);

    // 使用 xlsx-js-style 读取 Excel 文件
    const workbook = xlsx.read(data, {
      type: 'array',
      cellStyles: true,
      raw: true,
    });

    // 假设我们只处理第一个工作表
    const sheetName = workbook.SheetNames[0];
    const worksheet = workbook.Sheets[sheetName];
    // 将工作表转换为 JSON 格式
    const jsonData = xlsx.utils.sheet_to_json(worksheet, {
      header: 1,
      raw: true,
    });

    return jsonData ?? [];
  }

  // 排序
  sortAndFilterObjects(objects, attributeOrder) {
    return objects.map((obj: any) => {
      // 创建一个新对象，只包含指定的属性，并按照属性顺序排列
      const newObj = {};
      attributeOrder.forEach(attr => {
        if (obj.hasOwnProperty(attr)) {
          newObj[attr] = obj[attr];
        }
      });
      return newObj;
    });
  }
}
